package org.mushroomdb.transaction;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.mushroomdb.interceptor.CompositeInterceptor;
import org.mushroomdb.interceptor.Interceptor;
import org.mushroomdb.interceptor.InterceptorService;
import org.mushroomdb.lock.LockService;
import org.mushroomdb.lock.locktypes.Lock;
import org.mushroomdb.security.SecurityInterceptor;
import org.mushroomdb.security.SecurityService;
import org.mushroomdb.service.ServiceManager;

/**
 * @author Tomas
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
public class Transaction {
    
    //TODO ver de poner una estructura mas copada
    
    private List<TransactionalResource> resources = new ArrayList<TransactionalResource>();
    private ThreadLocal<Boolean> stackedOp = new ThreadLocal<Boolean>();
  //  private Timer timer = new Timer();
  // private TrxTimerTask task;
  //  private static long DEADLOCK_TIME = 60000;
     
    
    public Transaction(){
        this.removeStackedOp();
  //      task = new TrxTimerTask(this, Thread.currentThread());
    }
    
    //TODO Check This
    private List<Lock> locks = new ArrayList<Lock>();
    
    public void commit(){
        Iterator<TransactionalResource> iter = this.resources.iterator();
        while(iter.hasNext()){
            TransactionalResource resource = iter.next();
            resource.onCommit();
        }
        
        Iterator<Lock> iter2 = this.locks.iterator();
        
        while(iter2.hasNext()){
            Lock lock = iter2.next();
            LockService lockService = (LockService) ServiceManager.getInstance().getService(LockService.class);
            SecurityService service = (SecurityService) ServiceManager
            .getInstance().getService(SecurityService.class);
            SecurityInterceptor interceptor = getSecurityInterceptor();
            interceptor.setToken();
            lockService.unlock(lock);
            interceptor.removeToken();
        }
        
    //    this.timer.cancel();
        
             
    }
    
    public void rollback(){
        
        Iterator<TransactionalResource> iter = this.resources.iterator();
        while(iter.hasNext()){
            TransactionalResource resource = iter.next();
            resource.onRollback();
        }
        
        Iterator<Lock> iter2 = this.locks.iterator();
        
        while(iter2.hasNext()){
            Lock lock = iter2.next();
            LockService lockService = (LockService) ServiceManager.getInstance().getService(LockService.class);
          SecurityService service = (SecurityService) ServiceManager
          .getInstance().getService(SecurityService.class);
//          SecurityInterceptor interceptor = getSecurityInterceptor();
//          interceptor.setToken();
          lockService.unlock(lock);
//          interceptor.removeToken();
        }
        
      //  this.timer.cancel();
    }

    /**
     * @param trxRegister
     */
    public void append(TransactionalResource trxResource) {
        if(!this.resources.contains(trxResource)){
            this.resources.add(trxResource);
            trxResource.onBeginTrx();
        }
    }

    /**
     * @param lock
     */
    public void appendLock(Lock lock) {
     //   this.task.start();
        if(this.locks.isEmpty()){
            //es el primer lock
     //       this.timer.schedule(this.task,Transaction.DEADLOCK_TIME,Transaction.DEADLOCK_TIME);
        }
        this.locks.add(lock);
     //   this.task.skip();
  
    }

    /**
     * @return
     */
    public boolean isStacked() {
        return this.stackedOp.get().booleanValue();
    }

    /**
     * 
     */
    public void setStackedOp() {
       this.stackedOp.set(Boolean.TRUE);        
    }
    
    public void removeStackedOp() {
        this.stackedOp.set(Boolean.FALSE);        
     }
    
    public List<TransactionalResource> getResources() {
        return this.resources;
    }
    
    private SecurityInterceptor getSecurityInterceptor() {
        InterceptorService interceptorService = InterceptorService.getInstance();
        CompositeInterceptor compositeInterceptor = (CompositeInterceptor) interceptorService.getInterceptor();
        List<Interceptor> interceptors = compositeInterceptor.getInterceptors();
        Iterator<Interceptor> iter = interceptors.iterator();
        
        while(iter.hasNext()){
            Interceptor interceptor = iter.next();
            if(interceptor instanceof SecurityInterceptor){
                return (SecurityInterceptor)interceptor;
            }
        }
        return null;
    }
}
